package com.nebula.core.dsl.operation;

import com.nebula.core.constant.Constant;
import com.nebula.core.entity.vo.Vertex;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.util.*;

import static com.nebula.core.constant.Constant.QUOTED_LITERAL_FORMAT;

/**
 * 顶点操作类
 *
 * @author zhangtao
 */
@Slf4j
public class VertexOperation {

    /**
     * 插入点
     * INSERT VERTEX <tag_name> (<property_name>[, <property_name>...])[, <tag_name> (<property_name>[, <property_name>...]), ...]
     * {VALUES | VALUE}
     * <vid>: (<property_value>[, <property_value>...])[, <vid>: (<property_value>[, <property_value>...];
     *
     * @param tagName
     * @param vertexList
     * @return
     */
    protected static String insertVertex(String tagName, List<Vertex> vertexList) {
        if (StringUtils.isBlank(tagName)) {
            throw new RuntimeException("tagName is not empty");
        }

        if (CollectionUtils.isEmpty(vertexList)) {
            throw new RuntimeException("vertexList is not empty");
        }

        List<String> columns = new ArrayList<>();
        if (!CollectionUtils.isEmpty(vertexList.get(0).getProperties())) {
            for (Map.Entry<String, Object> entry : vertexList.get(0).getProperties().entrySet()) {
                if (Constant.VID.equalsIgnoreCase(entry.getKey())) {
                    continue;
                }
                columns.add(entry.getKey());
            }
        }

        StringBuilder ngql = new StringBuilder("INSERT VERTEX ");
        ngql.append(tagName);

        StringJoiner columsJoin = new StringJoiner(",", "(", ")");
        columns.forEach(c -> columsJoin.add(c));
        ngql.append(columsJoin);

        ngql.append(" VALUES ");

        StringJoiner vertexJoin = new StringJoiner(",");
        for (Vertex vertex : vertexList) {
            StringJoiner valuesJoin = new StringJoiner(",", String.format(QUOTED_LITERAL_FORMAT, vertex.getVid()) + ":(", ")");
            if (!CollectionUtils.isEmpty(vertex.getProperties())) {
                for (Map.Entry<String, Object> entry : vertex.getProperties().entrySet()) {
                    if (Constant.VID.equalsIgnoreCase(entry.getKey())) {
                        continue;
                    }
                    Object value = entry.getValue();
                    if (value instanceof Number) {
                        valuesJoin.add(value.toString());
                    } else if (value instanceof Date) {
                        Date d = (Date) value;
                        valuesJoin.add(String.format(Constant.TIMESTAMP_FORMAT, d.getTime() / 1000));
                    } else {
                        valuesJoin.add(String.format(QUOTED_LITERAL_FORMAT, value));
                    }
                }
            }
            vertexJoin.add(valuesJoin.toString());
        }
        ngql.append(vertexJoin);

        return ngql.toString();
    }

    /**
     * 删除点
     *
     * @param vids
     * @return
     */
    protected static String deleteVertex(String... vids) {
        if (vids.length == 0) {
            throw new IllegalArgumentException("vids is not empty");
        }
        StringBuilder ngql = new StringBuilder("DELETE VERTEX ");
        StringJoiner vidsJoin = new StringJoiner(",");
        Arrays.stream(vids).forEach(c -> vidsJoin.add(String.format(QUOTED_LITERAL_FORMAT, c)));
        ngql.append(vidsJoin);
        return ngql.toString();
    }

    protected static String updateVertex(String tagName, Vertex vertex) {
        if (StringUtils.isBlank(tagName)) {
            throw new IllegalArgumentException("tagName is not empty");
        }

        StringBuilder ngql = new StringBuilder("UPDATE VERTEX ON ");
        ngql.append(tagName);

        ngql.append(String.format(" '%s' ", vertex.getVid()));

        StringJoiner valuesJoin = new StringJoiner(",", " SET ", "");

        if (!CollectionUtils.isEmpty(vertex.getProperties())) {
            for (Map.Entry<String, Object> entry : vertex.getProperties().entrySet()) {
                Object value = entry.getValue();
                if (value instanceof Number) {
                    valuesJoin.add(String.format("%s = %s", entry.getKey(), value));
                } else if (value instanceof Date) {
                    Date d = (Date) value;
                    valuesJoin.add(String.format("%s = timestamp(%s)", entry.getKey(), d.getTime() / 1000));
                } else {
                    valuesJoin.add(String.format("%s = '%s'", entry.getKey(), value));
                }
            }
        }

        ngql.append(valuesJoin);
        return ngql.toString();
    }
}
